﻿using System;
using NUnit.Framework;
using System.Linq;
using SilentVoice.Models;
using System.Collections.Generic;

namespace SilentVoice.Data.Tests
{
    [TestFixture]
    public class UserManagementTests
    {
        [TestFixtureSetUp]
        public void Setup()
        {
            TestData.Create();
        }

        [TestFixtureTearDown]
        public void TearDown()
        {
            TestData.Wipe();
        }

        [Test]
        public void BasicAccountCRUD()
        {
            Account mitAccount = new Account()
            {
                Name = "MIT"
            };

            UserManagement userManager = new UserManagement();

            //Create
            Account createdAccount = userManager.CreateAccount(mitAccount);
            Assert.NotNull(createdAccount, "Created account was null.");
            Assert.That(mitAccount.Equals(createdAccount),
                "Created account was not the same as what was passed in");

            //Read
            Account readMitAccount = userManager.GetAccount(2);
            Assert.NotNull(readMitAccount, "Existing account retrieved was null.");
            Assert.That(readMitAccount.Equals(createdAccount),
                "Retrieved account was not the same as what was inserted.");

            //Update
            createdAccount.Name = "MIT Inc.";
            Account updatedAccount = userManager.UpdateAccount(createdAccount);
            Assert.NotNull(updatedAccount, "Updated account was null.");
            Assert.That(updatedAccount.Name.Equals(updatedAccount.Name), "Account was not updated");

            //Check updated
            Account updatedMITInc = userManager.GetAccount(2);
            Assert.NotNull(updatedMITInc, "Updated account retrieved was null.");
            Assert.That(createdAccount.Equals(updatedMITInc),
                "Account was actually never updated in database. Updated: {0} | Retrieved: {1}", createdAccount, updatedMITInc);

            //Delete
            Account deletedAccount = userManager.DeleteAccount(createdAccount);
            Assert.NotNull(deletedAccount, "Deleted account retrieved was null.");

            //Check deleted
            Account checkDeleted = userManager.GetAccount(2);
            Assert.Null(checkDeleted, "Account was never deleted");

            //Get account users
            ICollection<User> noblesUsers = userManager.GetAccountUsers(new Account() { Id=1 });
            Assert.NotNull(noblesUsers, "List of users should not have been null");
            Assert.That(noblesUsers.SingleOrDefault(x => x.Id == 1) != null 
                && noblesUsers.SingleOrDefault(x => x.Id == 2) != null, 
                "Both seed users should have been in the list");

            //Get account groups
            ICollection<Group> noblesGroups = userManager.GetAccountGroups(new Account() { Id = 1 });
            Assert.NotNull(noblesGroups, "List of groups should not have been null");
            Assert.That(noblesGroups.SingleOrDefault(x => x.Id == 1) != null
                && noblesGroups.SingleOrDefault(x => x.Id == 2) != null,
                "Both seed groups should have been in the list");
        }

        [Test]
        public void BasicUserCRUD()
        {
            User andyUser = new User()
            {
                FirstName = "Andy",
                MiddleName = "Marks",
                LastName = "User",
                AccountId = 1,
                Designation = "7th Grader",
                Email = "Andy.User@gmail.com",
                PasswordSalt = "123456",
                PasswordHash = "124556",
                RoleId = 2
            };

            UserManagement userManager = new UserManagement();

            //Create
            User createdUser = userManager.CreateUser(andyUser);
            Assert.NotNull(createdUser, "Created user was null.");
            Assert.That(andyUser.Equals(createdUser),
                "Created user was not the same as what was passed in");

            //Read
            User readMitUser = userManager.GetUser(3);
            Assert.NotNull(readMitUser, "Existing user retrieved was null.");
            Assert.That(readMitUser.Equals(createdUser),
                "Retrieved user was not the same as what was inserted.");

            //Update
            createdUser.Designation = "8th Grader";
            User updatedUser = userManager.UpdateUser(createdUser);
            Assert.NotNull(updatedUser, "Updated user was null.");
            Assert.That(createdUser.Designation.Equals(updatedUser.Designation), "User was not updated");

            //Check updated
            User updatedAndy8th = userManager.GetUser(3);
            Assert.NotNull(updatedAndy8th, "Updated user retrieved was null.");
            Assert.That(createdUser.Equals(updatedAndy8th),
                "User was actually never updated in database. Updated: {0} | Retrieved: {1}", createdUser, updatedAndy8th);

            //Delete
            User deletedUser = userManager.DeleteUser(createdUser);
            Assert.NotNull(deletedUser, "Deleted user retrieved was null.");

            //Check deleted
            User checkDeleted = userManager.GetUser(3);
            Assert.Null(checkDeleted, "User was never deleted");
        }

        [Test]
        public void BasicGroupCRUD()
        {
            Group tenthGraders = new Group()
            {
                Name = "10th Graders",
                AccountId = 1
            };

            UserManagement userManager = new UserManagement();

            //Create
            Group createdGroup = userManager.CreateGroup(tenthGraders);
            Assert.NotNull(createdGroup, "Created group was null.");
            Assert.That(tenthGraders.Equals(createdGroup),
                "Created group was not the same as what was passed in");

            //Read
            Group readGroup = userManager.GetGroup(3);
            Assert.NotNull(readGroup, "Existing group retrieved was null.");
            Assert.That(readGroup.Equals(createdGroup),
                "Retrieved group was not the same as what was inserted.");

            //Update
            createdGroup.Name = "11th Graders";
            Group updatedUser = userManager.UpdateGroup(createdGroup);
            Assert.NotNull(updatedUser, "Updated group was null.");
            Assert.That(createdGroup.Name.Equals(updatedUser.Name), "Group was not updated");

            //Check updated
            Group updated11th = userManager.GetGroup(3);
            Assert.NotNull(updated11th, "Updated group retrieved was null.");
            Assert.That(createdGroup.Equals(updated11th),
                "Group was actually never updated in database. Updated: {0} | Retrieved: {1}", createdGroup, updated11th);

            //Delete
            Group deletedUser = userManager.DeleteGroup(createdGroup);
            Assert.NotNull(deletedUser, "Deleted group retrieved was null.");

            //Check deleted
            Group checkDeleted = userManager.GetGroup(3);
            Assert.Null(checkDeleted, "Group was never deleted");

            //Get group users
            ICollection<User> fourthGradeUsers = userManager.GetGroupUsers(new Group() { Id = 1 });
            Assert.NotNull(fourthGradeUsers, "List of users should not have been null");
            Assert.That(fourthGradeUsers.SingleOrDefault(x => x.Id == 2) != null,
                "There should have been a user in the list");
        }

        [Test]
        public void LoginTests()
        {
            User amyUser = new User()
            {
                FirstName = "Amy",
                LastName = "User",
                Designation = "",
                AccountId = 1,
                Email = "mycroft@lol.com",
                RoleId = 2
            };

            UserManagement userManager = new UserManagement();
            
            //Test registration
            User createdUser = userManager.Register(amyUser, "sn0rkLe");
            Assert.NotNull(createdUser, "Could not register user");
            Assert.AreEqual(amyUser, createdUser, "User was not properly created in database");

            //Test (good) login
            User loggedInUser = userManager.Login("mycroft@lol.com", "sn0rkLe");
            Assert.NotNull(loggedInUser, "Could not log in as user");
            Assert.AreEqual(amyUser, loggedInUser, "User was not properly returned from database upon login");

            //Test bad login (bad password)
            Assert.Throws<Models.Exceptions.BadLogin>(new TestDelegate(
                () => {User badLogin = userManager.Login("mycroft@lol.com", "sn0rklee");})
            );

            //Test bad login (bad username)
            Assert.Throws<Models.Exceptions.BadLogin>(new TestDelegate(
                () => { User badLogin = userManager.Login("mycroft@loll.com", "sn0rkLe"); })
            );

            
        }
    }
}
